﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.IO;
using System.Web;
using Microsoft.SharePoint.Utilities;
using System.Net;
using System.Data.SqlClient;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using SPThumbnailExtender.TimerJob;
using System.Data;
using System.Data.SqlTypes;



namespace SPThumbnailExtender.Interne
{
    internal static class Helper
    {
        internal const int Img_Width = 800;
        internal const int Img_Height = 600;
        private static object _oSync = new object();
        private static SqlConnection cndata = null;

        internal static Guid GetDocumentID(Uri FileUrl)
        {
            return GetDocumentID(FileUrl, false);

        }

        internal static SqlConnection GetSQLConnection()
        {
            if (cndata == null)
                cndata = new SqlConnection(Helper.GetParameter("SPThumbnailExtender.ConnectionString").ToString());
            if (cndata.State != ConnectionState.Open)
                cndata.Open();
            return cndata;
        }
        internal static Guid GetDocumentID(Uri FileUrl, bool Insert)
        {
            SqlConnection cndata = GetSQLConnection();
            lock (_oSync)
            {
                using (SqlCommand cmdata = new SqlCommand("select ID from documents where FileUrl=@FileUrl", cndata))
                {
                    cmdata.Parameters.AddWithValue("@FileUrl", FileUrl.AbsoluteUri);
                    object o = null;
                    using (SqlDataReader drData = cmdata.ExecuteReader())
                    {
                        if (drData.Read())
                            o = drData.GetSqlValue(0);
                        drData.Close();
                    }

                    if (o == null && Insert)
                        using (SqlCommand cmdataInsert = new SqlCommand("insert into documents (Name, FileUrl, InsertTime) values(@FileName, @FileUrl, @InsertTime)", cndata))
                        {
                            string FileName = Path.GetFileNameWithoutExtension(FileUrl.AbsolutePath);
                            cmdataInsert.Parameters.AddWithValue("@FileName", FileName);
                            cmdataInsert.Parameters.AddWithValue("@FileUrl", FileUrl.AbsoluteUri);
                            cmdataInsert.Parameters.AddWithValue("@InsertTime", DateTime.Now);
                            cmdataInsert.ExecuteNonQuery();
                            return GetDocumentID(FileUrl);
                        }
                    Guid guidReturn;
                    if (o == null)
                        guidReturn = Guid.Empty;
                    else
                        guidReturn = new Guid(o.ToString());
                    return guidReturn;
                }
            }



        }
        internal static DateTime? GetDocumentDate(Uri FileUrl)
        {
            SqlConnection cndata = GetSQLConnection();
            object o = null;
            lock (_oSync)
            {
                using (SqlCommand cmdata = new SqlCommand("select InsertTime from documents where FileUrl=@FileUrl", cndata))
                {
                    cmdata.Parameters.AddWithValue("@FileUrl", FileUrl.AbsoluteUri);
                    using (SqlDataReader drData = cmdata.ExecuteReader())
                    {
                        if (drData.Read())
                            o = drData.GetSqlValue(0);
                        drData.Close();
                    }
                }
                
            }
            if (o == null)
                return null;
            DateTime DateReturn = DateTime.Parse(o.ToString());
            return DateReturn;



        }
        internal static void GetThumbnail(Uri FileUrl, int pageNumber, out Bitmap bmp)
        {
            SqlConnection cndata = GetSQLConnection();
            lock (_oSync)
            {
                using (SqlCommand cmdata = new SqlCommand("select PageThumbnail from documents inner join Thumbnail on documents.id=Thumbnail.documentid where FileUrl=@FileUrl and PageNumber=@PageNumber", cndata))
                {

                    cmdata.Parameters.AddWithValue("@FileUrl", FileUrl.AbsoluteUri);
                    cmdata.Parameters.AddWithValue("@PageNumber", pageNumber);
                    object o = null;
                    using (SqlDataReader drData = cmdata.ExecuteReader())
                    {
                        if (drData.Read())
                            o = drData.GetSqlValue(0);
                        drData.Close();
                    }

                    if (o == null)
                        bmp = new Bitmap(typeof(Helper).Assembly.GetManifestResourceStream("SPThumbnailExtender.thumbext100.png"));
                    else
                    {
                        byte[] imageContent = ((SqlBinary)o).Value;
                        MemoryStream ms = new MemoryStream(imageContent);
                        bmp = new Bitmap(ms);
                    }

                }
            }
        }
        internal static void DeleteThumbnailsForDocument(Uri FileUrl)
        {
            Guid guidDocument = GetDocumentID(FileUrl);
            if (guidDocument == Guid.Empty)
                return;

            SqlConnection cndata = GetSQLConnection();
            lock (_oSync)
            {

                using (SqlCommand cmdata = new SqlCommand("delete from thumbnail where DocumentID=@DocumentID", cndata))
                {
                    cmdata.Parameters.AddWithValue("@DocumentID", guidDocument);
                    cmdata.ExecuteNonQuery();


                }
            }
        }
        internal static void DeleteThumbnail(Uri FileUrl, int PageNumber)
        {
            Guid guidDocument = GetDocumentID(FileUrl);
            if (guidDocument == Guid.Empty)
                return;

            SqlConnection cndata = GetSQLConnection();
            lock (_oSync)
            {
                using (SqlCommand cmdata = new SqlCommand("delete from thumbnail where DocumentID=@DocumentID and PageNumber=@PageNumber", cndata))
                {
                    cmdata.Parameters.AddWithValue("@DocumentID", guidDocument);
                    cmdata.Parameters.AddWithValue("@PageNumber", PageNumber);
                    cmdata.ExecuteNonQuery();
                }
            }
        }
        internal static void InsertThumbnail(Uri FileUrl, int PageNumber, Bitmap Thumbnail)
        {
            if (Thumbnail == null)
                return;

            int imgWidth;
            int imgHeight;
            string strResolution = "";
            if (Helper.GetParameter("SPThumbnailExtender.Resolution") != null)
                strResolution = Helper.GetParameter("SPThumbnailExtender.Resolution").ToString();

            switch (strResolution)
            {
                case "1":
                    imgWidth = 640;
                    imgHeight = 480;
                    break;
                case "2":
                    imgWidth = 800;
                    imgHeight = 600;
                    break;
                case "3":
                    imgWidth = 1024;
                    imgHeight = 768;
                    break;
                case "4":
                    imgWidth = 1280;
                    imgHeight = 1024;
                    break;
                default:
                    imgHeight = Img_Height;
                    imgWidth = Img_Width;
                    break;


            }
            using (Image img = FixedSize(Thumbnail, imgWidth, imgHeight))
            {

                Guid guidDocument = GetDocumentID(FileUrl, true);

                SqlConnection cndata = GetSQLConnection();
                lock (_oSync)
                {
                    using (SqlCommand cmdata = new SqlCommand("insert into thumbnail (DocumentID, PageNumber,PageThumbnail, ThumbnailSize) values (@DocumentID,@PageNumber, @PageThumbnail, @ThumbnailSize)", cndata))
                    {
                        cmdata.Parameters.AddWithValue("@DocumentID", guidDocument);
                        cmdata.Parameters.AddWithValue("@PageNumber", PageNumber);
                        using (MemoryStream ms = new MemoryStream())
                        {
                            img.Save(ms, ImageFormat.Png);
                            byte[] imageContent = ms.ToArray();
                            cmdata.Parameters.AddWithValue("@PageThumbnail", imageContent);
                            cmdata.Parameters.AddWithValue("@ThumbnailSize", ms.Length);
                            cmdata.ExecuteNonQuery();
                        }
                    }

                }
            }
        }
        internal static DateTime GetDateTimeFile(Uri url)
        {
            using (SPSite site = new SPSite(url.AbsoluteUri))
            {
                using (SPWeb web = site.OpenWeb())
                {
                    SPFile file = web.GetFile(url.AbsoluteUri);
                    DateTime dtReturn = (file.TimeLastModified == DateTime.MinValue) ? file.TimeCreated : file.TimeLastModified;
                    return file.TimeLastModified;
                }
            }
        }
        internal static void GetBitmapFromUri(Uri uri, out Bitmap bmp)
        {
            try
            {
                HttpWebRequest myRequest = (HttpWebRequest)HttpWebRequest.Create(uri);

                myRequest.Credentials = CredentialCache.DefaultCredentials;
                using (HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse())
                {
                    Stream inputStream = myResponse.GetResponseStream();
                    MemoryStream outputStream = new MemoryStream();
                    BinaryReader reader = new BinaryReader(inputStream);
                    BinaryWriter writer = new BinaryWriter(outputStream);
                    byte[] buffer = new byte[16384];
                    int bytesRead;
                    while ((bytesRead = reader.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        writer.Write(buffer, 0, bytesRead);
                    }
                    writer.Flush();

                    outputStream.Position = 0;
                    bmp = new Bitmap(outputStream);
                }
            }
            catch
            {
                bmp = null; // if for some reason we couldn't get to image, we return null
            }

        }
        internal static Image FixedSize(Image imgPhoto, int Width, int Height)
        {
            float widthRatio = imgPhoto.VerticalResolution / imgPhoto.HorizontalResolution;
            int sourceWidth = (int)(imgPhoto.Width * widthRatio);
            int sourceHeight = imgPhoto.Height;
            int destX = 0;
            int destY = 0;

            float nPercent = 0;
            float nPercentW = 0;
            float nPercentH = 0;

            nPercentW = ((float)Width / (float)sourceWidth);
            nPercentH = ((float)Height / (float)sourceHeight);
            if (nPercentH < nPercentW)
            {
                nPercent = nPercentH;
                destX = System.Convert.ToInt16((Width -
                              (sourceWidth * nPercent)) / 2);
            }
            else
            {
                nPercent = nPercentW;
                destY = System.Convert.ToInt16((Height -
                              (sourceHeight * nPercent)) / 2);
            }

            int destWidth = (int)(sourceWidth * nPercent);
            int destHeight = (int)(sourceHeight * nPercent);

            Bitmap bmPhoto = new Bitmap(destWidth, destHeight,
                              PixelFormat.Format24bppRgb);
            //bmPhoto.SetResolution(imgPhoto.HorizontalResolution,imgPhoto.VerticalResolution);
            bmPhoto.SetResolution(96.0f, 96.0f);

            Graphics grPhoto = Graphics.FromImage(bmPhoto);
            grPhoto.Clear(Color.White);
            grPhoto.InterpolationMode =
                    InterpolationMode.HighQualityBicubic;
            grPhoto.SmoothingMode = SmoothingMode.HighSpeed;
            grPhoto.DrawImage(imgPhoto,
                new Rectangle(0, 0, destWidth, destHeight));

            grPhoto.Dispose();
            return bmPhoto;

        }
        internal static string GetSourceFilename(string url, int width, int height, int iPage, string extension)
        {
            Uri uri = new Uri(url);
            string shortFilename = uri.Host.Replace(".", "_") +
                            uri.LocalPath.Replace("/", "_");
            shortFilename += String.Format("-P{0}-{1}x{2}", iPage > 0 ? iPage.ToString() : "%d", width, height) + extension;
            return GetPath(extension) + shortFilename;

        }
        internal static string GetPath(string extension)
        {
            string strPath = SPUtility.GetGenericSetupPath(@"Template\Layouts\SPThumbnailExtender");
            strPath = strPath + "\\Cached" + extension.Replace(".", "").ToUpper() + "\\";
            if (!Directory.Exists(strPath))
                Directory.CreateDirectory(strPath);
            return strPath;
        }
        internal static byte[] ReadToEnd(System.IO.Stream stream)
        {
            long originalPosition = stream.Position;
            stream.Position = 0;

            try
            {
                byte[] readBuffer = new byte[4096];

                int totalBytesRead = 0;
                int bytesRead;

                while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
                {
                    totalBytesRead += bytesRead;

                    if (totalBytesRead == readBuffer.Length)
                    {
                        int nextByte = stream.ReadByte();
                        if (nextByte != -1)
                        {
                            byte[] temp = new byte[readBuffer.Length * 2];
                            Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
                            Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
                            readBuffer = temp;
                            totalBytesRead++;
                        }
                    }
                }

                byte[] buffer = readBuffer;
                if (readBuffer.Length != totalBytesRead)
                {
                    buffer = new byte[totalBytesRead];
                    Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
                }
                return buffer;
            }
            finally
            {
                stream.Position = originalPosition;
            }
        }
        internal static DateTime GetDateTime(Uri FileUri, string DateValue)
        {
            DateTime dateReturn;
            using (SPSite site = new SPSite(FileUri.AbsoluteUri))
            {
                using (SPWeb web = site.OpenWeb())
                {
                    dateReturn = SPUtility.ParseDate(web, DateValue, SPDateFormat.DateTime, true);
                }
            }
            return dateReturn;
        }
        internal static bool IsFileExist(Uri FileUri)
        {
            bool bReturn = false;
            using (SPSite site = new SPSite(FileUri.AbsoluteUri))
            {
                using (SPWeb web = site.OpenWeb())
                {
                    bReturn = web.GetFile(FileUri.AbsoluteUri).Exists;
                }
            }
            return bReturn;
        }
        internal static bool IsDocumentExistInDatabase(Uri FileUrl)
        {
            object o = null;
            SqlConnection cndata = GetSQLConnection();
            lock (_oSync)
            {
                using (SqlCommand cmdata = new SqlCommand("select ID from documents where FileUrl=@FileUrl", cndata))
                {
                    cmdata.Parameters.AddWithValue("@FileUrl", FileUrl.AbsoluteUri);
                    using (SqlDataReader drData = cmdata.ExecuteReader())
                    {

                        if (drData.Read())
                            o = drData.GetSqlValue(0);
                        drData.Close();
                    }
                }
            }
            if (o == null)
                return false;
            else
                return true;


        }
        internal static void SetParameter(string ParameterName, string ParameterValue)
        {
            if (SPFarm.Local.Properties.ContainsKey(ParameterName))
                SPFarm.Local.Properties[ParameterName] = ParameterValue;
            else
                SPFarm.Local.Properties.Add(ParameterName, ParameterValue);
            SPFarm.Local.Update();
        }
        internal static object GetParameter(string ParameterName)
        {
            if (SPFarm.Local.Properties.ContainsKey(ParameterName))
                return SPFarm.Local.Properties[ParameterName];
            else
                return null;
        }
        internal static void CreateWorkItem(Uri FileUri)
        {

            if (IsDocumentExistInDatabase(FileUri))
                return;
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                using (SPSite curSite = new SPSite(SPContext.Current.Site.ID))
                {
                    using (SPWeb curWeb = curSite.OpenWeb(SPContext.Current.Web.ID))
                    {
                        curSite.AddWorkItem(Guid.Empty,
                          DateTime.Now.ToUniversalTime(),
                          new Guid(ThumbnailExtenderTimerJobWI.WITID),
                          curWeb.ID,
                          curWeb.ID,
                          1,
                          false,
                          Guid.Empty,
                          Guid.Empty,
                          0,
                          null,
                          FileUri.AbsoluteUri,
                          Guid.Empty);
                    }
                }
            });
        }
        internal static int GetCacheThumbnailCount(Uri FileUri)
        {
            int iReturn;

            SqlConnection cndata = GetSQLConnection();
            lock (_oSync)
            {
                using (SqlCommand cmdata = new SqlCommand("select COUNT(Thumbnail.ID) from Thumbnail inner join documents on Thumbnail.DocumentID=Documents.ID where Documents.FileURL=@FileUrl", cndata))
                {
                    cmdata.Parameters.AddWithValue("@FileUrl", FileUri.AbsoluteUri);
                    object o = null;
                    using (SqlDataReader drData = cmdata.ExecuteReader())
                    {
                        if (drData.Read())
                            o = drData.GetSqlValue(0);
                        drData.Close();
                    }

                    iReturn = (o == null) ? 0 : (int.Parse(o.ToString()));
                }
            }

            return iReturn;
        }


        internal static bool IsDocumentNeedUpdate(Uri FileUri)
        {
            if (!Helper.IsDocumentExistInDatabase(FileUri))
                return true;


            DateTime? TimeInsert = Helper.GetDocumentDate(FileUri);
            if (!TimeInsert.HasValue)
                return true;

            if (!IsSiteExists(FileUri))
                if (TimeInsert.Value.AddDays(30) < DateTime.Now)
                    return true;

            DateTime TimeDocument = Helper.GetDateTimeFile(FileUri);
            if (TimeInsert.Value < TimeDocument)
                return true;

            return false;
        }
        public static bool IsSiteExists(Uri SiteUri)
        {
            SPSite site = null;
            try
            {
                site = new SPSite(SiteUri.AbsoluteUri);
            }
            catch (FileNotFoundException e)
            {
                return false;
            }
            finally
            {
                if (site != null) site.Dispose();
            }
            return true;
        }

    }
}
